/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.ipercube.impl.simple;

import com.ipercube.model.AxisValue;
import com.ipercube.model.Node;
import com.ipercube.model.Tree;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author tartur
 */
public class SimpleAxisValueTree<T extends AxisValue> implements Tree<T, Integer> {

    private Node<T, Integer> root;

    public SimpleAxisValueTree() {
        root = new Node<T, Integer>(null, null, -1);
    }

    public void add(T parent, T axisValue) {
        Node<T,Integer> p = findNode(parent);
        createChildNode(p, axisValue);
    }

    public void remove(T axisValue) {
        Node<T,Integer> n = findNode(axisValue);
        if(n != null){
            n.getParent().removeChild(n);
        }
    }

    private Node<T, Integer> createChildNode(Node<T, Integer> parent, T node) {
        return new Node<T, Integer>(parent, node, parent.getDepth() + 1);
    }

    public List<Node<T, Integer>> getNodesByDepth(int depth) {
        int childLevel = root.getDepth();
        Node<T, Integer> parent = null;
        Node<T, Integer> children = root;
        while (childLevel < axisValue.getLevel()) {
            childLevel++;
            parent = child;
            for (Node<T, Integer> node : parent.getChildren()) {
                if (eq(node, axisValue, childLevel)) {
                    child = node;
                }
            }
            if (child == null) {
                throw new RuntimeException("There is no value for " + axisValue);
            }
        }
        if (child == root) {
            throw new RuntimeException("There is no value for " + axisValue);
        }
        return child;
    }

    public Node<T, Integer> getNodeByIndexAt(int depth, int index) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public int getNodesCount(int depth) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public int getDepth() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public Node<T, Integer> findNode(T axisValue) {
        int childLevel = root.getDepth();
        Node<T, Integer> parent = null;
        Node<T, Integer> child = root;
        while (childLevel < axisValue.getLevel()) {
            childLevel++;
            parent = child;
            for (Node<T, Integer> node : parent.getChildren()) {
                if (eq(node, axisValue, childLevel)) {
                    child = node;
                }
            }
            if (child == null) {
                throw new RuntimeException("There is no value for " + axisValue);
            }
        }
        if (child == root) {
            throw new RuntimeException("There is no value for " + axisValue);
        }
        return child;
    }

    protected boolean eq(Node<T, Integer> n1, Node<T, Integer> n2, int l) {
        if (n1 == null) {
            return false;
        }
        if (n2 == null) {
            return false;
        }
        if (n1.getNode() == null && n2.getNode() == null) {
            return true;
        }
        if (n1.getNode() == null || n2.getNode() == null) {
            return false;
        }
        Object o1 = n1.getNode().getValueByLevel(l);
        Object o2 = n2.getNode().getValueByLevel(l);
        if (o1 == null && o2 == null) {
            return true;
        }
        return o1 != null && o1.equals(o2);
    }

    protected boolean eq(Node<T, Integer> n, T v, int l) {
        if (n == null) {
            return false;
        }
        if (n.getNode() == null && v == null) {
            return true;
        }
        if (n.getNode() == null || v == null) {
            return false;
        }
        Object o1 = n.getNode().getValueByLevel(l);
        Object o2 = v.getValueByLevel(l);
        if (o1 == null && o2 == null) {
            return true;
        }
        return o1 != null && o1.equals(o2);
    }
}
